/**
 * 
 */
package cn.bblocks.cacheTest.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.bblocks.cacheTest.model.Area;
import cn.bblocks.cacheTest.model.dao.AreaMapper;
import cn.bblocks.cacheTest.service.AreaService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Administrator
 * 自动缓存方案：
 * 0、key得机制，key直接是主键值 or key为 &a=1&b=2&c=* =》 key = "#result.areaid" 或者  key = "'&areaCode='+#p0"
 * 1、del：无需特别处理，即可确保查询最新数据(删除一条，当缓存数据List中含本条数据会导致组织失败，重新执行查询)
 * 2、update：需要显示告知更新字段，比如更新了：userid=2、b=3、c=4字段，
 *           a、如果3个字段不影响查询结果，执行A
 *           b、如果嫌麻烦直接执行B（后果集合都无效会走DB，但是简单）
 *           c、明确知道则 执行C  @CachePut(key = "#result.areaid") 和 @Caching( evict = {@CacheEvict(key = "'&userId'.concat('=').concat(#P0.userid)").concat('&')})      
 *           d、只知道改了3个字段则：2个办法
 *                             	方案：C @CachePut(key = "#result.areaid") 和 @Caching( evict = {@CacheEvict(key = "'&userId=*&b=*&c=*&'")})      
 *                                                                              方案：D 标准变更的字段 @CachePut(key = "#result.areaid")   和  @CacheUpdate(key = "#fields")
 * 	  其他的复杂查询暂时不考虑，比如in,>,>=等查询（其实可以了）
 * 3、add:原则上清除 id查询之外的全部结果集合比较合适(如果不能指定的话) 
 *           a、B方案
 *           b、C明确知道 （举个例子：银行卡管理，一般按id查询以及查询用户下的银行卡， XX添加了一张银行卡，则很明确）
 * 4、批量清除方案：
 *    a、循环删除（查找需要优化）
 *    b、通过版本号增加为 主动不用前一版本的集合（静待失效时间到）
 * 5、缓存更新方案：
 * 	  A、简单字段更新，不需要处理集合换成，执行：@CachePut(key = "#result.areaid")  
 *    B、简单粗暴，清除全部集合：@CachePut(key = "#result.areaid") 和 @CacheEvict(allEntries=true) ，清除集合2个方案：1、循环删除（集群有问题），2、通过增加版本号达到批量失效以及进入新的版本空间
 *    C、明确知道影响集合，比如：@CachePut(key = "#result.areaid") 和 @Caching( evict = {@CacheEvict(key = "'&userId'.concat('=').concat(#onebank.idcardseqno).concat('&')")}) 
 *    D、只知道改了几个字段（主要是update）@CachePut(key = "#result.areaid")   和  @CacheUpdate(key = "#fields")
 */
@Data
@Slf4j
@Service
@CacheConfig(cacheNames = "Area") 
public class AreaServiceImpl implements AreaService {
	

	@Autowired
	AreaMapper areaMapper;
	
	 @Cacheable( key = "'&parentId='+#p0")
	 public List<Area> getChildren(Integer areaId) {
		 return areaMapper.findByParentidOrderByAreaid(areaId);
	 }
	
	@Cacheable( key = "'&areaCode='+#p0")
	 public Area selectByCode(String code) {
		 return areaMapper.findByAreacode(code);
	 }
	
	 @Cacheable(key = "#id")  
	 public Area selectByPrimaryKey(Integer id) {
		 return areaMapper.findById(id).orElse(null);
	 }
	 
	  
	 //3个方案：1、清空全部 2、清空全部 非ID的，3、指定几个查询  ：,
	 //比如增加银行卡接口，存在接口：我的银行卡，添加银行卡 则添加银行，方案以此为：1、清除全部 2、清除 带 “&*”（可能会部分问题大于等的key搜不到）  3、清除指定的几个查询（带通配符）4、清除我的银行卡 ，从效果来看看 后面的效果更好，从快速开发性来说前面更优
//	 @CacheEvict(allEntries=true)
//	 @Caching( evict = {@CacheEvict(key = "'&parentId'.concat('*')"), @CacheEvict(key = "'&areaCode'.concat('*')")})
	 @Caching( evict = {@CacheEvict(key = "'&*'")})
	 public Area insertSelective(Area area) {
		 areaMapper.saveAndFlush(area);
		 return area;
	 }
	 
	 //比较完美，如果修改的是核心的查询字段 ，比如上面的：areaCode，parentId，则需要通知
//	 @Transactional
	 @CachePut(key = "#result.areaid")  
	// @CacheUpdate(key = "#fields")
	 public Area updateByPrimaryKey(Area area,String... fields) {
		// selectByPrimaryKey(area.getAreaid());
		 
		 areaMapper.saveAndFlush(area);
		 return area;
	 }
	 
	 //完美()
	 @Transactional  
	 @CacheEvict(key = "#areaId") 
	 public void deleteByPrimaryKey(Integer areaId) {
		  areaMapper.deleteById(areaId);
	 }

	 

	
}
